package net.yakiboo.util;


import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Enumeration;
import java.util.LinkedList;
import java.util.List;

import android.util.Log;
import android.widget.ToggleButton;

import net.yakiboo.adrums.Song;

public class ClientServer {
    /** Called when the activity is first created. */
	
	private List<String> connections;
	private List<String> songs;
	
	private boolean isServer = false, recording=false, start=false, stop=false, merge=false;
	private String ip="0.0.0.0";
	
	private Thread client, server;
	
	private String clientMessage="";
	private String serverMessage="";
	private String message="";
	private String song="";	
	
	public ClientServer(){
		connections = new LinkedList<String>();
        songs = new LinkedList<String>();
    }
	
	public String getSongtoString(){
		return song;
	}
	
	public Song getSong(){
		Song s=new Song();
		if(!song.equals("")){
			try{
				String[] soundandtime = song.split("\n");
				String[] sounds = soundandtime[0].split(" ");
				String[] times = soundandtime[1].split(" ");
				
				for(int i=0; i<sounds.length;i++)
					s.getSound().add(Integer.parseInt(sounds[i]));
				for(int i=0; i<times.length;i++)
					s.getTime().add(Double.parseDouble(times[i]));
			}catch(ArrayIndexOutOfBoundsException e){
				Log.e("ClientServer", "Error al devolver la cancion: Cancion vacia o defectuosa");
				s.getSound().add(1);
				s.getTime().add(15.0);
			}
		}
		return s;
	}

	public void setSong(Song s){
		String contenido="";
       	if(s!=null){
    		for(int i=0; i<s.getSound().size();i++)
    			contenido+=s.getSound().get(i) + " ";
    		contenido+="\n";
    		for(int i=0; i<s.getTime().size();i++)
    			contenido+=s.getTime().get(i) + " ";
       	}
       	song=contenido;
	}
	
	public Song string2song(String song){
		Song s=new Song();
		if(!song.equals("")){
			try{
				String[] soundandtime = song.split("\n");
				String[] sounds = soundandtime[0].split(" ");
				String[] times = soundandtime[1].split(" ");
				
				for(int i=0; i<sounds.length;i++)
					s.getSound().add(Integer.parseInt(sounds[i]));
				for(int i=0; i<times.length;i++)
					s.getTime().add(Double.parseDouble(times[i]));
			}catch(ArrayIndexOutOfBoundsException e){
				Log.e("ClientServer", "Error al devolver la cancion: Cancion vacia o defectuosa");
			}
		}
		return s;
	}
	
	public String song2string(Song s){
		String contenido="";
       	if(s!=null){
    		for(int i=0; i<s.getSound().size();i++)
    			contenido+=s.getSound().get(i) + " ";
    		contenido+="\n";
    		for(int i=0; i<s.getTime().size();i++)
    			contenido+=s.getTime().get(i) + " ";
       	}
       	return contenido;
	}
	
	public boolean getStop() {
		return stop;
	}

	public void setStop(boolean stop) {
		this.start = stop;
	}
    
    public boolean getStart() {
		return start;
	}

	public void setStart(boolean start) {
		this.start = start;
	}

	public boolean getIsServer() {
		return this.isServer;
	}

	public void setIsServer(boolean isServer) {
		this.isServer = isServer;
	}

	public boolean isRecording() {
		return recording;
	}

	public void setRecording(boolean recording) {
		this.recording = recording;
	}

	public void onStop(){
    	isServer=!isServer;
    	stopThreads();
    }
    
	private void espera(long time){
		try {
			Thread.sleep(time);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
    public void loadIP(){
    	Runnable runnable = new Runnable(){
			@Override
			public void run() {
				try {
			        for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) {
			            NetworkInterface intf = en.nextElement();
			            for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) {
			                InetAddress inetAddress = enumIpAddr.nextElement();
			                if (!inetAddress.isLoopbackAddress()) {
			                    ip = inetAddress.getHostAddress().toString();
			                }
			            }
			        }
			    } catch (SocketException e) {
			       e.printStackTrace();
			    }
			}
    	};
    	new Thread(runnable).start();
    }
    
    public String getIP(){
    	return this.ip;
    }
    
    public void setIP(String ip){
    	this.ip=ip;
    }
    
    public String mergeSong(String ss1, String ss2){
    	String merge="";
    	Song smerge=new Song();
    	Song s1=string2song(ss1);
    	Song s2=string2song(ss2);
    	int cont=s1.getSound().size()+s2.getSound().size(), cont1=0, cont2=0;
    	
    	while(cont>=0){
    		if(s1.getSound().size()>cont1)
    			if(s2.getSound().size()>cont2)
		    		if(s1.getTime().get(cont1)<=s2.getTime().get(cont2)){
		    			smerge.getSound().add(s1.getSound().get(cont1));
		    			smerge.getTime().add(s1.getTime().get(cont1));
		    			cont1++;
		    		}else{
		    			smerge.getSound().add(s2.getSound().get(cont));
		    			smerge.getTime().add(s2.getTime().get(cont2));
		    			cont2++;
		    		}
    			else{
    				smerge.getSound().add(s1.getSound().get(cont1));
	    			smerge.getTime().add(s1.getTime().get(cont1));
	    			cont1++;
    			}
    		else if(s2.getSound().size()>cont2){
    			smerge.getSound().add(s2.getSound().get(cont));
    			smerge.getTime().add(s2.getTime().get(cont2));
    			cont2++;
    		}
    		cont--;
    	}
    	
    	merge=song2string(smerge);
    	return merge;
    }
    
    private boolean sameSongs(){
    	boolean b=true;
    	for(int s=0;s<songs.size()-1;s++)
    		if(!songs.get(s).equals("merged"))
    			b=false;
    	return b;
    }
    
    public void serverJob(){    	
    	Runnable runnable = new Runnable(){
    		DataInputStream in=null;
			DataOutputStream out=null;
			Socket socket=null;
			ServerSocket serverSocket=null;
	    	
			@Override
			public void run() {
				try {
					serverSocket = new ServerSocket(3333);
					System.out.println("Listening: 3333");
					isServer=true;
				} catch (IOException e1) {
					e1.printStackTrace();
				}
				while(isServer){
					try {
						socket = serverSocket.accept();
					    in = new DataInputStream(socket.getInputStream());
					    out = new DataOutputStream(socket.getOutputStream());
					    if(!connections.contains(socket.getInetAddress().toString())){
					    	connections.add(socket.getInetAddress().toString());
					    	songs.add("unmerged");
					    }
					    serverMessage=in.readUTF();
					    
					    if(serverMessage.equals("rq@")){ //request state
							if(!recording)
								clientMessage="nrec@";
							else
								clientMessage="rec@";
					    }else if(serverMessage.equals("start@")){ //start recording
					    	start=true;
					    	clientMessage="";
					    }else if(serverMessage.startsWith("end@")){ //record finished + song
					    	stop=true;
							clientMessage="";
							for(int c=0;c<connections.size();c++)
								if(connections.get(c).equals(socket.getInetAddress().toString())){
									if(songs.size()>c){
										song=mergeSong(song,serverMessage.substring(4));
										songs.set(c, "merged");
									}
								}							
					    }else if(serverMessage.equals("rqf@"))
					    	if(sameSongs())
					    		clientMessage="song@"+song;
					    
					    out.writeUTF(clientMessage);
					    clientMessage="";
					    
					    if(stop){
							stop=false;
							recording=false;
						}
						if(start){
							start=false;
							recording=true;
						}
					} catch (IOException e) {
						e.printStackTrace();
					} catch (NullPointerException npe){
						npe.printStackTrace();
					}finally{
						if (socket != null){
				    		try {
				    			socket.close();
				    		} catch (IOException e){
				    			e.printStackTrace();
				    		}
				    	}
				
				    	if (out != null){
				    		try {
				    			out.close();
				    		} catch (IOException e) {
				    			e.printStackTrace()	;
				    		}
				    	}
				
				    	if (in != null){
				    		try {
				    			in.close();
				    		} catch (IOException e) {
				    			e.printStackTrace();
				    		}
				    	}
					} //finally
				} //while
				if (serverSocket != null){
		    		try {
		    			serverSocket.close();
		    		} catch (IOException e){
		    			e.printStackTrace();
		    		}
		    	}
				
			} //run
    	};
    	server = new Thread(runnable);
    	server.start();
    }
    
    public void clientJob(String serverIP){
    	this.ip=serverIP;
    	isServer=false;
    	Runnable runnable = new Runnable(){
    		DataInputStream dataInputStream=null;
			DataOutputStream dataOutputStream=null;
			Socket socket=null;
			@Override
			public void run() {
				while(!isServer){
					try {
						
						espera(200);
						
						if(ip.matches("[0-9]{0,3}.[0-9]{0,3}.[0-9]{0,3}.[0-9]{0,3}")){
							socket = new Socket(ip, 3333);
							dataOutputStream = new DataOutputStream(socket.getOutputStream());
							if(merge)
								serverMessage="rqf@";
							else{
								if(recording){
									if(stop){
										serverMessage="end@"+song;
										stop=false;
										recording=false;
										merge=true;
									}else
										serverMessage="rq@";
								}else{
									if(start){
										serverMessage="start@";
										start=false;
										recording=true;
									}else
										serverMessage="rq@";
								}
							}
							dataOutputStream.writeUTF(serverMessage);
							serverMessage="";
							dataInputStream = new DataInputStream(socket.getInputStream());
							
							message=dataInputStream.readUTF();
							
							if(message.equals("nrec@")){
								if(recording)
									stop=true;
							}else if(message.equals("rec@")){
								if(!recording)
									recording=true;
							}else if(message.startsWith("song@"))
								song=message.substring(5);
						}
					} catch (UnknownHostException e) {
						e.printStackTrace();
					} catch (IOException e) {
						e.printStackTrace();
					}
				    finally{
				    	if (socket != null){
				    		try {
				    			socket.close();
				    		} catch (IOException e){
				    			e.printStackTrace();
				    		}
				    	}
				
				    	if (dataOutputStream != null){
				    		try {
				    			dataOutputStream.close();
				    		} catch (IOException e) {
				    			e.printStackTrace()	;
				    		}
				    	}
				
				    	if (dataInputStream != null){
				    		try {
				    			dataInputStream.close();
				    		} catch (IOException e) {
				    			e.printStackTrace();
				    		}
				    	}
				    }//finally
				}//while
			}//run
    	};
    	client = new Thread(runnable);
    	client.start();
    }
    
    public void stopThreads(){
    	Thread s,c;
    	c=client;
    	s=server;
    	client=null;
    	server=null;
    	if(s!=null)
    		s.interrupt();
    	if(c!=null)
    		c.interrupt();
    }
    
}


